//
//  LBReactMultiPatcher.m
//  LBReactMultiPatcher
//
//  Created by WuShiHai on 19/5/24.
//  Copyright (c) 2019 Lebbay All rights reserved.
//

#import "LBReactMultiPatcher.h"

#import <Masonry/Masonry.h>

#import <LBFoundation/LBFoundation.h>
#import <LBUIKit/LBUIKit.h>
#import <LBNetworking/LBNetworking.h>
#import <LBNetworking/LBAPP.h>
#import <LBDownloader/LBDownloader.h>

//#import <LBEncrypt/LBAES.h>

#import "LBReactPatcher.h"
#import "LBReactMultiPatcher.h"
#import "LBDatabase.h"
#import "LBReactPatcherModel.h"
#import "LBReactPatcherResponseModel.h"
#import "LBReactPatcherDao.h"
#import "LBReactPatcherConfigurationHeader.h"

@interface LBReactMultiPatcher() {
    dispatch_group_t _downloadPatchersGroup;
    NSLock *_lock;
}

@property (nonatomic, assign) BOOL isUpgrading;

@property (nonatomic, strong) NSMutableDictionary *modulesExecuteTimeMap;

@property (nonatomic, assign) NSUInteger mainVersion;

@property (nonatomic, strong) NSString *baseUrl;

//@property (nonatomic, weak) UIView *dialog;

@end

@implementation LBReactMultiPatcher

+ (instancetype)manager {
    static LBReactMultiPatcher *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[LBReactMultiPatcher alloc] init];
    });
    return instance;
}

- (instancetype)init {
    if (self = [super init]) {
        _downloadPatchersGroup = dispatch_group_create();
        _lock = [[NSLock alloc] init];
        _mainVersion = 0;
        [self addObserver];
    }
    return self;
}

- (void)dealloc {
    [self removeObserver];
}

#pragma mark - Public Method
- (void)setBaseUrl:(NSString *)baseUrl {
    _baseUrl = baseUrl;
}

- (void)upgrade:(LBReactMultiPatcherUpgradeCompleteBlock)complete {
    if (!self.isUpgrading) {
        self.isUpgrading = YES;
        
        if (self.mainVersion == 0) {
            self.mainVersion = [self localMainVersion];
        }
        
        [self updateAllBusiness:nil
                         bridge:nil
                       isRender:NO
                       progress:nil
                       complete:^(BOOL isSuccess, NSError *error, BOOL isUpdate) {
            //有更新 并且成功下载
            LBBlockSafeRun(complete, isSuccess, error, isUpdate);
            self.isUpgrading = NO;
        }];
    }
}

- (void)renderMainBundle:(NSDictionary *)launchOptions
                isRender:(BOOL)isRender
        isUseDefaultOnly:(BOOL)isUseDefaultOnly
                progress:(LBReactMultiPatcherDownloadProgressBlock)progress
                complete:(LBReactBridgeRenderCompleteBlock)complete {
    void(^renderComplete)(BOOL isSuccess, NSError *error, BOOL isUpdate) = ^(BOOL isSuccess, NSError *error, BOOL isUpdate){
        if (error) {
            LBBlockSafeRun(complete, isSuccess, error, NO);
        } else {
            [self renderLocalAllBusiness:launchOptions
                                  bridge:LBReactBridgeManager.bridge
                                isRender:isRender
                                complete:complete];
            
//            if (isUseDefaultOnly) {
//                [self renderDefaultAllBusiness:launchOptions
//                                        bridge:LBReactBridgeManager.bridge
//                                      isRender:isRender
//                                      complete:complete];
//            } else {
                //此处已不支持更新，必须调用upgrade方法
//                [self updateAllBusiness:launchOptions
//                                 bridge:LBReactBridgeManager.bridge
//                               isRender:isRender
//                               progress:progress
//                               complete:complete];
//            }
        }
    };
                
    self.mainVersion = [self localMainVersion];
    
    [[LBReactBridge manager] render:LBReactBridgeMultiMode
                         bundlePath:nil
                         bundleName:@"business/main/index.main"
                      launchOptions:launchOptions
                           complete:renderComplete];
}

- (void)renderBusinessBundle:(LBReactBridgeRenderLevel)level
                      bridge:(LBBridge *)bridge
                      module:(NSString *)module
                    complete:(LBReactBridgeRenderCompleteBlock)complete {
#define FetchModuleAction() \
    void(^requestComplete)(BOOL isSuccess, NSError *error, BOOL isUpdate) = ^(BOOL isSuccess, NSError *error, BOOL isUpdate) {    \
        if (isSuccess) {    \
            LBBlockSafeRun(complete, isSuccess, error, NO); \
        } else {    \
            [self renderLocalBusinessBundle:module  \
                                     bridge:bridge  \
                                   complete:complete];  \
        }   \
    };  \
    [self request:bridge    \
           module:module    \
         complete:requestComplete]; \

#define loadLocalModuleAction() \
    void(^localComplete)(BOOL isSuccess, NSError *error, BOOL isUpdate) = ^(BOOL isSuccess, NSError *error, BOOL isUpdate) {  \
        if (isSuccess) {    \
            LBBlockSafeRun(complete, isSuccess, error, NO); \
        } else {    \
            [self request:bridge    \
                   module:module    \
                 complete:complete];    \
        }   \
    };  \
    [self renderLocalBusinessBundle:module  \
                             bridge:bridge  \
                           complete:localComplete];
    
    if (level == LBReactBridgeRenderEveryFetchLevel) {
        FetchModuleAction();
    } else if (level == LBReactBridgeRenderPriorityLocalLevel) {
        loadLocalModuleAction();
    } else if (level == LBReactBridgeRenderFetchInIntervalLevel) {
        if ([self isNeedFetchModule:module]) {
            FetchModuleAction();
        } else {
            loadLocalModuleAction();
        }
    } else {
        LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(LevelUnKown), NO);
    }
    
#undef FetchModuleAction()
#undef loadLocalModuleAction()
    
}

- (void)renderLocalBusinessBundleWith:(LBReactPatcherModel *)patcher
                               bridge:(LBBridge *)bridge
                             complete:(LBReactBridgeRenderCompleteBlock)complete {
    //这里需要判断主包应该在加载中或者已经加载
    if (patcher) {
        [self download:bridge
               patcher:patcher
              complete:complete];
    } else {
        LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(BundleNotFound), NO);
    }
}

- (LBReactPatcherModel *)localLatestPatcherWith:(NSString *)module {
    return [self localValidPatcher:module];
}

#pragma mark - Download Method
- (void)updateAllBusiness:(NSDictionary *)launchOptions
                   bridge:(LBBridge *)bridge
                 isRender:(BOOL)isRender
                 progress:(LBReactMultiPatcherDownloadProgressBlock)progress
                 complete:(LBReactBridgeRenderCompleteBlock)complete {
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *patcherModules = [self localPatchers];
    
    void (^requestComplete)(LBBaseResponse *response, NSError *error) = ^(LBBaseResponse *response, NSError *error){
        if (error) {
            LBBlockSafeRun(complete, NO, error, NO);
        } else {
            NSDictionary<NSString *, LBReactPatcherModel *> *patchers =
            [NSDictionary yy_modelDictionaryWithClass:[LBReactPatcherModel class]
                                                 json:response.data];
            
            //will download
            [patchers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, LBReactPatcherModel * _Nonnull obj, BOOL * _Nonnull stop) {
                obj.isWillDownlod = YES;
            }];
            
            //根据最新的bundleid，设置本地已下载的包状态
            [self batchUpdateLocalPatcherState:patchers];
            
            LBBlockSafeRun(progress, 0.3);
            [patcherModules addEntriesFromDictionary:patchers];
            [self downloadAllBusinesses:[patcherModules allValues]
                                 bridge:bridge
                               isRender:isRender
                               progress:progress
                               complete:complete];
        }
    };
    [self requestAll:patcherModules
            progress:progress
            complete:requestComplete];
}

- (void)renderDefaultAllBusiness:(NSDictionary *)launchOptions
                          bridge:(LBBridge *)bridge
                        isRender:(BOOL)isRender
                        complete:(LBReactBridgeRenderCompleteBlock)complete {
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *patcherModules = [self defaultPatcherModules];
    [self downloadAllBusinesses:[patcherModules allValues]
                         bridge:bridge
                       isRender:isRender
                       progress:nil
                       complete:complete];
}

- (void)renderLocalAllBusiness:(NSDictionary *)launchOptions
                        bridge:(LBBridge *)bridge
                      isRender:(BOOL)isRender
                      complete:(LBReactBridgeRenderCompleteBlock)complete {
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *patcherModules = [self localExistPatchers];
    [self downloadAllBusinesses:[patcherModules allValues]
                         bridge:bridge
                       isRender:isRender
                       progress:nil
                       complete:complete];
}

- (void)downloadAllBusinesses:(NSArray<LBReactPatcherModel *> *)patchers {
    [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull patcher, NSUInteger idx, BOOL * _Nonnull stop) {
        //donoting
        void(^downloaderComplete)(BOOL isSuccess, LBDownloaderModel *downloader) = ^(BOOL isSuccess, LBDownloaderModel *downloader) {
            //保存信息
            if (isSuccess) {
                if ([[self patcherDao] insert:patcher]) {
                    //do nothong
                } else {
                    //do nothong
                }
            } else {
                //do nothong
            }
        };
        [[LBDownloader manager] start:patcher.url
                                unzip:YES
                                cache:NO
                             progress:nil
                             complete:downloaderComplete];
    }];
}

- (void)downloadAllBusinesses:(NSArray<LBReactPatcherModel *> *)patchers
                      bridge:(LBBridge *)bridge
                    isRender:(BOOL)isRender
                    progress:(LBReactMultiPatcherDownloadProgressBlock)progress
                    complete:(LBReactBridgeRenderCompleteBlock)complete {
    NSMutableDictionary<NSString *, NSString *> *downloaderFolderMaps = [@{} mutableCopy];
    __block BOOL isUpdate = NO;
    [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull patcher, NSUInteger idx, BOOL * _Nonnull stop) {
        dispatch_group_enter(_downloadPatchersGroup);
        
        //有下载的说明需要更新
        if (patcher.isWillDownlod) {
            isUpdate = YES;
        }
        
        //本地已有的
        if (patcher.isBundleResouce) {
            [_lock lock];
            [downloaderFolderMaps setObject:patcher.bundleModulePath
                                     forKey:patcher.moduleName];
            [_lock unlock];
            dispatch_group_leave(_downloadPatchersGroup);
        } else {
            void(^downloaderComplete)(BOOL isSuccess, LBDownloaderModel *downloader) = ^(BOOL isSuccess, LBDownloaderModel *downloader) {
                //保存信息
                if (isSuccess) {
                    if ([[self patcherDao] insert:patcher]) {
                        [_lock lock];
                        [downloaderFolderMaps setObject:[[downloader unzipFolderPath] stringByAppendingPathComponent:patcher.moduleName]
                                                 forKey:patcher.moduleName];
                        [_lock unlock];
                    } else {
                        //do nothing
                    }
                } else {
                    //do nothing
                }
                dispatch_group_leave(_downloadPatchersGroup);
            };
            void(^downloadProgress)(NSProgress *downloadProgress) = ^(NSProgress *downloadProgress) {
                patcher.downloadProgress =  downloadProgress.completedUnitCount * 1.0 / downloadProgress.totalUnitCount;
                __block CGFloat progressValue = 0.3/** 已经请求完接口*/;
                // 加载JS的时间忽略不计
                [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    progressValue += (0.7 / [patchers count] * obj.downloadProgress);
                }];
                LBBlockSafeRun(progress, MIN(1, progressValue));
            };
            [[LBDownloader manager] start:patcher.url
                                    unzip:YES
                                    cache:NO
                                 progress:downloadProgress
                                 complete:downloaderComplete];
        }
    }];
    
    dispatch_queue_t disqueue = dispatch_queue_create("com.lebbay.patcher", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_notify(_downloadPatchersGroup, disqueue, ^{
        if ([downloaderFolderMaps allValues].count == patchers.count) {
            if (isRender) {
                [self renderAllBusinesses:[downloaderFolderMaps copy]
                                 patchers:patchers
                                   bridge:bridge
                                 complete:complete];
            } else {
                LBBlockSafeRunInMain(complete, YES, nil, isUpdate);
            }
        } else {
            LBBlockSafeRunInMain(complete, NO, LBReactBridgeRenderError(Downloader), NO);
        }
    });
}

- (void)download:(LBBridge *)bridge
         patcher:(LBReactPatcherModel *)patcher
        complete:(LBReactBridgeRenderCompleteBlock)complete {
    void(^downloaderComplete)(BOOL isSuccess, LBDownloaderModel *downloader) = ^(BOOL isSuccess, LBDownloaderModel *downloader) {
        //保存信息
        if (isSuccess) {
            if ([[self patcherDao] insert:patcher]) {
                [self renderBusiness:bridge
                             patcher:patcher
                          downloader:downloader
                            complete:complete];
            } else {
                //保存失败的话
                LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(DataBaseSave), NO);
            }
        } else {
            LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(Downloader), NO);
        }
    };
    [[LBDownloader manager] start:patcher.url
                            unzip:YES
                            cache:NO
                         progress:nil
                         complete:downloaderComplete];
}

#pragma mark - Render Method
- (void)renderAllBusinesses:(NSDictionary<NSString *, NSString *> *)downloaderFolderMaps
                   patchers:(NSArray<LBReactPatcherModel *> *)patchers
                     bridge:(LBBridge *)bridge
                   complete:(LBReactBridgeRenderCompleteBlock)complete {
    NSMutableArray<LBBridgeModuleInfo *> *moduleInfos = [@[] mutableCopy];
    NSMutableData *allSourceCode = [[NSMutableData alloc] initWithCapacity:0];
    
    __block BOOL isContinue = YES;
    [downloaderFolderMaps enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *folderPath, BOOL * _Nonnull stop) {
        NSString *moduleFolderPath = folderPath;
        LBReactPatcherModel *patcher = [[patchers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"moduleName == %@", key]] firstObject];
        NSError *error = nil;
        NSData *sourceCode = [NSData dataWithContentsOfFile:[LBReactBridge pathOfJSBundleIn:moduleFolderPath]
                                                    options:NSDataReadingMappedIfSafe
                                                      error:&error];
        if (error) {
            LBBlockSafeRunInMain(complete, NO, error, NO);
            isContinue = NO;
            *stop = YES;
        } else {
            LBBridgeModuleInfo *moduleInfo = [[LBBridgeModuleInfo alloc] init];
            moduleInfo.name = patcher.moduleName;
            moduleInfo.index = patcher.bundleId;
            moduleInfo.folderPath = moduleFolderPath;
            [moduleInfos addObject:moduleInfo];            
            [allSourceCode appendData:sourceCode];
        }
//        if ([LBReactBridge copyAssetFolder:[folderPath stringByAppendingPathComponent:patcher.moduleName]
//                                        to:LBReactBridgeManager.bundlePath]) {
//            NSError *error = nil;
//            NSData *sourceCode = [NSData dataWithContentsOfFile:[LBReactBridge pathOfJSBundleIn:folderPath]
//                                                        options:NSDataReadingMappedIfSafe
//                                                          error:&error];
//            if (error) {
//                LBBlockSafeRunInMain(complete, NO, error);
//                isContinue = NO;
//                *stop = YES;
//            } else {
//                LBBridgeModuleInfo *moduleInfo = [[LBBridgeModuleInfo alloc] init];
//                moduleInfo.name = patcher.moduleName;
//                moduleInfo.index = patcher.bundleId;
//                moduleInfo.folderPath = folderPath;
//                [moduleInfos addObject:moduleInfo];
//                [allSourceCode appendData:sourceCode];
//            }
//        } else {
//            LBBlockSafeRunInMain(complete, NO, LBReactBridgeRenderError(OperationFolder));
//            isContinue = NO;
//            *stop = YES;
//        }
    }];
    
    if (isContinue) {
        [LBReactBridgeManager executeSourceCodeIn:bridge
                                       sourceCode:[allSourceCode copy]
                                      moduleInfos:[moduleInfos copy]
                                           module:@"launch"
                                         complete:complete];
    }
}

- (void)renderLocalBusinessBundle:(NSString *)module
                           bridge:(LBBridge *)bridge
                         complete:(LBReactBridgeRenderCompleteBlock)complete {
    //这里需要判断主包应该在加载中或者已经加载
    LBReactPatcherModel *patcher = [self localValidPatcher:module];
    [self renderLocalBusinessBundleWith:patcher
                                 bridge:bridge
                               complete:complete];
}

- (void)renderBusiness:(LBBridge *)bridge
               patcher:(LBReactPatcherModel *)patcher
            downloader:(LBDownloaderModel *)downloader
              complete:(LBReactBridgeRenderCompleteBlock)complete {
    [[LBReactBridge manager] executeSourceCodeIn:bridge
                                      folderPath:[[downloader unzipFolderPath] stringByAppendingPathComponent:patcher.moduleName]
                                          module:patcher.moduleName
                                           index:patcher.bundleId 
                                        complete:complete];
}

#pragma mark - Request Method
- (void)requestAll:(NSMutableDictionary<NSString *, LBReactPatcherModel *> *)patcherModules
          progress:(LBReactMultiPatcherDownloadProgressBlock)progress
          complete:(LBReactMultiPatcherReqeustCompleteBlock)complete {
    
    NSMutableDictionary *bundles = [@{} mutableCopy];
    [patcherModules enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, LBReactPatcherModel * _Nonnull obj, BOOL * _Nonnull stop) {
        [bundles setObject:obj.checkCode?:@"" forKey:key];
    }];
    
    LBBaseRequest *baseRequest = [LBBaseRequest defaultRequest:nil];
    baseRequest.data = @{
                         @"patchType": @(1),
                         @"bundleType": @(0),
                         @"mainVersion": @(self.mainVersion),
                         @"bundles": bundles
                         };
    NSDictionary *parameters = @{
        @"query": [baseRequest yy_modelToJSONString]
    };
    
    [self request:@"v1/patch/bundle/latest"
       parameters:parameters
         progress:progress
         complete:complete];
}

//单个请求暂时用不到，不支持
- (void)request:(LBBridge *)bridge
         module:(NSString *)module
       complete:(LBReactBridgeRenderCompleteBlock)complete {
    
    //请求服务器当前最新的补丁，下载然后应用
    void(^requestComplete)(LBBaseResponse *response, NSError *error) = ^(LBBaseResponse *response, NSError *error) {
        if (error) {
            LBBlockSafeRun(complete, NO, error, NO);
        } else {
             NSDictionary<NSString *, LBReactPatcherModel *> *patchers =
                       [NSDictionary yy_modelDictionaryWithClass:[LBReactPatcherModel class]
                                                            json:response.data];
            LBReactPatcherModel *patcher = [patchers objectForKey:module];
            //下载
            if (patcher.url.length > 0 && patcher.bundleId > 0) {
                [self download:bridge
                       patcher:patcher
                      complete:complete];
            } else {
                //没有新补丁
                LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(BundleNotFound), NO);
            }
        }
    };
    
    [self requestAll:nil
            progress:nil
            complete:requestComplete];
}

- (void)request:(NSString *)path
     parameters:(NSDictionary *)parameters
       progress:(LBReactMultiPatcherDownloadProgressBlock)progress
       complete:(LBReactMultiPatcherReqeustCompleteBlock)complete {
    NSString *host = self.baseUrl;
    NSString *URLString = [host stringByAppendingPathComponent:path];
    
    void(^success)(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) = ^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if ([responseObject isKindOfClass:[NSDictionary class]]) {
            LBBaseResponse *response = [LBBaseResponse yy_modelWithJSON:responseObject];
            if ([response isBlushMarkSuccess]) {
                LBBlockSafeRun(complete, response, nil);
            } else {
                LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(Server));
            }
        } else {
            LBBlockSafeRun(complete, nil, LBReactBridgeRenderError(ServerFormat));
        }
    };
    void(^failure)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) = ^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(Netwok));
    };
    void(^requestProgress)(NSProgress * _Nonnull downloadProgress) = ^(NSProgress * _Nonnull downloadProgress) {
        LBBlockSafeRun(progress, 0.3 * downloadProgress.completedUnitCount * 1.0 / downloadProgress.totalUnitCount);
    };
    [[LBHTTPSessionManager manager] GET:URLString
                             parameters:parameters
                               progress:requestProgress
                                success:success
                                failure:failure];
}

//未调用
- (void)response:(LBBridge *)bridge
            task:(NSURLSessionDataTask *)task
         success:(NSDictionary *)responseObject
        complete:(LBReactBridgeRenderCompleteBlock)complete {
    LBBaseResponse *response = [LBBaseResponse yy_modelWithJSON:responseObject];
    if ([response isBlushMarkSuccess]) {
        LBReactPatcherResponseModel *patcherResponse = [LBReactPatcherResponseModel yy_modelWithJSON:response.data];
        //下载
        if (patcherResponse.url.length > 0 && patcherResponse.bundleId > 0) {
            [self download:bridge
                   patcher:patcherResponse
                  complete:complete];
        } else {
            //没有新补丁
            LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(ServerFormat), NO);
        }
    } else {
        LBBlockSafeRun(complete, NO, LBReactBridgeRenderError(ServerFormat), NO);
    }
}

#pragma mark - Private Mthod
- (BOOL)isNeedFetchModule:(NSString *)module {
    NSDate *ever = [self.modulesExecuteTimeMap objectForKey:module];
    if (ever) {
        NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
        //60s
        NSTimeInterval threshold = 60;
        return (now - [ever timeIntervalSince1970]) > threshold;
    }
    return YES;
}

- (NSInteger)defaultMainVersion {
    return [[NSBundle stringValueWithConfigurationService:LBReactPatcherServiceConfiguration
                                                      key:LBReactPatcherServiceMainBundleVersion
                                             defaultValue:@"1"] integerValue] ;
}

- (NSUInteger)localMainVersion {
    NSFileManager *manager = [NSFileManager defaultManager];
    //1.获取文件夹下所有的子路径
    NSString *versionFilePath = [[[NSBundle mainBundle] resourcePath]
                                 stringByAppendingPathComponent:@"business/main/version"];
    NSString *version = [NSString stringWithContentsOfFile:versionFilePath
                                                  encoding:NSUTF8StringEncoding
                                                     error:nil];
    return [version integerValue];
}

- (NSMutableDictionary<NSString *, LBReactPatcherModel *> *)localPatchers {
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *l = [self localPatcherModules];
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *d = [self defaultPatcherModules];
    [d addEntriesFromDictionary:l];
    
    return d;
}

- (NSMutableDictionary<NSString *, LBReactPatcherModel *> *)localExistPatchers {
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *l = [self localPatcherModules];
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *d = [self defaultPatcherModules];
//    [d addEntriesFromDictionary:l];
    [l enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, LBReactPatcherModel * _Nonnull obj, BOOL * _Nonnull stop) {
        LBDownloaderModel *downloader = [[LBDownloaderModel alloc] init];
        downloader.isUnzip = YES;
        downloader.url = obj.url;
        
        LBDownloaderWork *work = [[LBDownloaderWork alloc] init];
        work.downloader = downloader;
        
        if ([work isDownloaded] && [work isUnziped]) {
            //替换
            [d setObject:obj forKey:key];
        }
    }];
    return d;
}

//- (NSString *)mainBundleName {
//    NSFileManager *manager = [NSFileManager defaultManager];
//    //1.获取文件夹下所有的子路径
//    NSString *folderPath = [[[NSBundle mainBundle] resourcePath]
//                            stringByAppendingPathComponent:@"business"];
//    NSArray *allPath =[manager subpathsAtPath:folderPath];
//
//    NSMutableDictionary<NSString *, LBReactPatcherModel *> *p = [@{} mutableCopy];
//
//    __weak __typeof(&*self) weakSelf = self;
//    [allPath enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
//        if ([obj isEqualToString:@"main"] == NO) {
//            NSString *moduleName = obj;
//            LBReactPatcherModel *patcher = [[LBReactPatcherModel alloc] init];
//            patcher.moduleName = moduleName;
//            patcher.isBundleResouce = YES;
//            patcher.bundleModulePath = [folderPath stringByAppendingPathComponent:obj];
//
//            NSString *checkFilePath = [patcher.bundleModulePath stringByAppendingPathComponent:@"check.key"];
//            NSString *checkCode = [NSString stringWithContentsOfFile:checkFilePath
//                                                            encoding:NSUTF8StringEncoding
//                                                               error:nil];
//            if (checkCode.length > 0) {
//                patcher.checkCode = checkCode;
//                [p setObject:patcher forKey:moduleName];
//            }
//
//            //            LBDownloaderWork *work = [[LBDownloaderWork alloc] init];
//            //            if ([work copyFile:[folderPath stringByAppendingPathComponent:obj]
//            //                       isUnzip:YES]) {
//            //                patcher.downloader = work.downloader;
//            //                NSString *checkFilePath =
//            //                [[[work.downloader unzipFolderPath]
//            //                  stringByAppendingPathComponent:moduleName]
//            //                 stringByAppendingPathComponent:@"check.key"];
//            //                NSString *checkCode = [NSString stringWithContentsOfFile:checkFilePath
//            //                                                                encoding:NSUTF8StringEncoding
//            //                                                                   error:nil];
//            //                if (checkCode.length > 0) {
//            //                    patcher.checkCode = checkCode;
//            //                    [p setObject:patcher forKey:moduleName];
//            //                }
//            //            }
//
//        }
//    }];
//    return p;
//}

- (NSMutableDictionary<NSString *, LBReactPatcherModel *> *)defaultPatcherModules {
    NSFileManager *manager = [NSFileManager defaultManager];
    //1.获取文件夹下所有的子路径
    NSString *folderPath = [[[NSBundle mainBundle] resourcePath]
                                stringByAppendingPathComponent:@"business"];
    NSArray *allPath =[manager subpathsAtPath:folderPath];
    
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *p = [@{} mutableCopy];
    
    __weak __typeof(&*self) weakSelf = self;
    [allPath enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isEqualToString:@"main"] == NO) {
            NSString *moduleName = obj;
            LBReactPatcherModel *patcher = [[LBReactPatcherModel alloc] init];
            patcher.moduleName = moduleName;
            patcher.isBundleResouce = YES;
            patcher.bundleModulePath = [folderPath stringByAppendingPathComponent:obj];
            
            NSString *checkFilePath = [patcher.bundleModulePath stringByAppendingPathComponent:@"check.key"];
            NSString *checkCode = [NSString stringWithContentsOfFile:checkFilePath
                                                            encoding:NSUTF8StringEncoding
                                                               error:nil];
            if (checkCode.length > 0) {
                patcher.checkCode = checkCode;
                [p setObject:patcher forKey:moduleName];
            }
            
//            LBDownloaderWork *work = [[LBDownloaderWork alloc] init];
//            if ([work copyFile:[folderPath stringByAppendingPathComponent:obj]
//                       isUnzip:YES]) {
//                patcher.downloader = work.downloader;
//                NSString *checkFilePath =
//                [[[work.downloader unzipFolderPath]
//                  stringByAppendingPathComponent:moduleName]
//                 stringByAppendingPathComponent:@"check.key"];
//                NSString *checkCode = [NSString stringWithContentsOfFile:checkFilePath
//                                                                encoding:NSUTF8StringEncoding
//                                                                   error:nil];
//                if (checkCode.length > 0) {
//                    patcher.checkCode = checkCode;
//                    [p setObject:patcher forKey:moduleName];
//                }
//            }
            
        }
    }];
    return p;
}

- (void)batchUpdateLocalPatcherState:(NSMutableDictionary<NSString *, LBReactPatcherModel *> *)localPatcherModules {
    LBReactPatcherDao *dao = [self patcherDao];
    NSArray<LBReactPatcherModel *> *patchers = [dao selectByVersion:[LBDeviceUtil appVersion]
                                                         identifier:[LBDeviceUtil bundleIdentifier]
                                                        mainVersion:self.mainVersion
                                                               type:LBReactPatcherTypeReactNative];
    [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        LBReactPatcherModel *latestPatcher = [localPatcherModules objectForKey:obj.moduleName];
        if (obj.bundleId == latestPatcher.bundleId) {
            //更新本地最新补丁state状态
            [dao updateState:obj];
        } else if (obj.bundleId > latestPatcher.bundleId) {
            //如果其他包比最新包还
            obj.state = 0;
            [dao updateState:obj];
        }
    }];
}

- (NSMutableDictionary<NSString *, LBReactPatcherModel *> *)localPatcherModules {
    LBReactPatcherDao *dao = [self patcherDao];
    NSMutableDictionary<NSString *, LBReactPatcherModel *> *p = [@{} mutableCopy];
    NSArray<LBReactPatcherModel *> *patchers = [dao selectByVersion:[LBDeviceUtil appVersion]
                                                         identifier:[LBDeviceUtil bundleIdentifier]
                                                             isMain:NO
                                                        mainVersion:self.mainVersion
                                                         moduleName:nil
                                                               type:LBReactPatcherTypeReactNative];
    [patchers enumerateObjectsUsingBlock:^(LBReactPatcherModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.moduleName.length > 0
            && ![p.allKeys containsObject:obj.moduleName]
            && ![p.allKeys containsObject:obj.moduleName]) {
            [p setValue:obj forKey:obj.moduleName];
        }
    }];
    return p;
}

- (LBReactPatcherModel *)localValidPatcher:(NSString *)moduleName {
    LBReactPatcherDao *dao = [self patcherDao];
    return [[dao selectByVersion:[LBDeviceUtil appVersion]
                      identifier:[LBDeviceUtil bundleIdentifier]
                          isMain:NO
                     mainVersion:self.mainVersion
                      moduleName:moduleName
                            type:LBReactPatcherTypeReactNative] firstObject];
}

- (LBReactPatcherDao *)patcherDao {
    static dispatch_once_t onceToken;
    static LBReactPatcherDao *dao = nil;
    dispatch_once(&onceToken, ^{
        LBDatabase *db = [LBDatabase database:@"patcher.db"];
        dao = [[LBReactPatcherDao alloc] initWithDatabase:db];
    });
    return dao;
}

- (NSMutableDictionary *)modulesExecuteTimeMap {
    if (_modulesExecuteTimeMap) {
        return _modulesExecuteTimeMap;
    }
    _modulesExecuteTimeMap = [@{} mutableCopy];
    return _modulesExecuteTimeMap;
}

- (void)addObserver {
    //暂时取消前后台更新
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appDidEnterForeground:)
                                                 name:UIApplicationWillEnterForegroundNotification
                                               object:nil];
}

- (void)removeObserver {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)appDidEnterForeground:(NSNotification *)notification {
    [self upgrade:nil];
}

//- (void)didCloseDialog {
//    [UIView animateWithDuration:0.3
//                     animations:^{
//        self.dialog.alpha = 0;
//    } completion:^(BOOL finished) {
//        [self.dialog removeFromSuperview];
//    }];
//}
//
//- (void)showUpdateDialog {
//    if (self.dialog) {
//        return;
//    }
//
//    UIView *dialog = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
//    self.dialog = dialog;
//
//    UIView *backgroundView = [[UIView alloc] initWithFrame:dialog.bounds];
//    backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
//    [dialog addSubview:backgroundView];
//
//    CGFloat margin = 15;
//    CGFloat height = 180;
//    UIView *contentView = [[UIView alloc] init];
//    contentView.backgroundColor = [UIColor colorWithWhite:1 alpha:1];
//    contentView.layer.masksToBounds = YES;
//    contentView.layer.cornerRadius = 5;
//    [dialog addSubview:contentView];
//    [contentView mas_makeConstraints:^(MASConstraintMaker *make) {
//        make.centerY.equalTo(dialog).with.offset(-IPHONE_BOTTOM_MARGIN);
//        make.left.equalTo(dialog).with.offset(margin);
//        make.right.equalTo(dialog).with.offset(-margin);
//    }];
//
//    UILabel *label = [[UILabel alloc] init];
//    label.font = [self appFontOfSize:13];
//    label.textColor = [UIColor colorWithHex:@"#333333"];
//    label.numberOfLines = 0;
//
//    NSString *text = @"The current page has been updated and reloaded for you.";
//    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
//    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
//    paragraphStyle.alignment = NSTextAlignmentCenter;
//    paragraphStyle.lineSpacing = 4;
//    [attributedText addAttribute:NSParagraphStyleAttributeName
//                           value:paragraphStyle
//                           range:NSMakeRange(0, text.length)];
//
//    label.attributedText = attributedText;
//    [contentView addSubview:label];
//    [label mas_makeConstraints:^(MASConstraintMaker *make) {
//        make.top.equalTo(contentView).with.offset(20);
//        make.left.equalTo(contentView).with.offset(margin);
//        make.right.equalTo(contentView).with.offset(-margin);
//    }];
//
//    UIButton *button = [[UIButton alloc] init];
//    button.titleLabel.font = [self boldAppFontOfSize:12];
//    [button setTitle:@"OK" forState:UIControlStateNormal];
//    [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
//    [button setBackgroundColor:[UIColor colorWithHex:@"#333333"]];
//    [button addTarget:self
//               action:@selector(didCloseDialog)
//     forControlEvents:UIControlEventTouchUpInside];
//    [contentView addSubview:button];
//    [button mas_makeConstraints:^(MASConstraintMaker *make) {
//        make.top.equalTo(label.mas_bottom).with.offset(20);
//        make.centerX.equalTo(contentView);
//        make.width.mas_equalTo(108);
//        make.height.mas_equalTo(30);
//        make.bottom.equalTo(contentView).with.offset(-15);
//    }];
//
//    dialog.alpha = 0;
//    [[UIApplication sharedApplication].keyWindow addSubview:dialog];
//    [UIView animateWithDuration:0.3
//                     animations:^{
//        dialog.alpha = 1;
//    }];
//
//}

//- (UIFont *)appFontOfSize:(CGFloat)fontSize {
//    return [UIFont fontWithName:@"Montserrat-Regular"
//                           size:fontSize];
//}
//
//- (UIFont *)boldAppFontOfSize:(CGFloat)fontSize {
//    return [UIFont fontWithName:@"Montserrat-Bold"
//                           size:fontSize];
//}

@end
